package ssq.utils.wolfmankill;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Scanner;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;

import ssq.utils.Base64Utils;
import ssq.utils.StrUtils;
import ssq.utils.wolfmankill.Participant.Role;
import ssq.utils.wolfmankill.Participant.Status;

public class WSServer extends WebSocketServer
{
    private static final String      SYSTEM_MSG   = "系统消息";
    private static final String      GOD          = "上帝";
    private static final Participant none         = new Participant("none");

    List<Participant>                participants = new LinkedList<Participant>();

    List<Participant>                voters       = new LinkedList<Participant>();
    List<String>                     votees       = new LinkedList<String>();
    HashMap<String, String>          voteHistory  = new HashMap<String, String>();
    int                              voteSize;
    int                              cntOfDead;
    protected boolean                gameEnd;
    private Participant              lastProtected;

    private Participant              lastKilled;
    private Participant              lastPoisoned;
    private LinkedList<Participant>  diedLastNight;
    private Participant              sergent;
    private boolean                  blameTheElder;
    int                              round;
    int                              cntOfWolves;
    State                            state;
    boolean                          poison;
    boolean                          save;
    
    public String toDetailedString()
    {
        StringBuilder sb = new StringBuilder(participants.toString());
        sb.append("\nlovers:").append(Arrays.asList(lover)).append("\ndiedLastNight").append(diedLastNight).append("\nround: ").append(round).append("\ncntOfDead: ").append(cntOfDead).append("\ncntOfWolves: ").append(cntOfWolves).append("\nstate: ").append(state).append("\nvoters : ").append(voters.toString()).append("\nvotees: ").append(votees.toString()).append("\nvoteHistory: ").append(voteHistory.toString()).append("\nvoteSize: ").append(voteSize);
        return sb.toString();
    }

    private void iniGame()
    {
        exited = new LinkedList<>();
        sergent = none;
        blameTheElder = false;
        gameEnd = false;
        round = 0;
        poison = true;
        save = true;
        cntOfDead = 0;
        cntOfWolves = 0;
        for (Role role : roles)
        {
            if (role == Role.狼人)
            {
                cntOfWolves++;
            }
        }
        lastProtected = none;

        participants = participants.subList(0, playerNum);
    }
    
    private void iniRound()
    {
        round++;
        lastKilled = none;
        lastPoisoned = none;
        diedLastNight = new LinkedList<>();
    }
    
    Participant[]                   lover  = new Participant[2];
    LinkedList<Role>                roles  = new LinkedList<Participant.Role>();
    int                             playerNum;
    private LinkedList<Participant> exited = new LinkedList<Participant>();

    enum State
    {
        wait,
        gamebegin,

        shuffle,
        盗贼,
        丘比特,

        roundbegin,
        预言家,
        守卫,
        狼人,
        女巫,
        lastWords,
        day,
        apply,
        vote,
        roundend,
        gameend
    }

    private void next()
    {
        if (state == State.day)
        {
            if (round == 1)
            {
                state = State.apply;
            }
            else
            {
                state = State.vote;
            }
        }
        else if (state == State.roundend)
        {
            if (gameEnd)
            {
                state = State.gameend;
            }
            else
            {
                state = State.roundbegin;
            }
        }
        else if (state == State.gameend)
        {
        }
        else
        {
            state = State.values()[state.ordinal() + 1];
        }

        try
        {
            Role role = Role.valueOf(state.toString());
            
            if (!roles.contains(role))
            {
                next();
            }
        }
        catch (Exception e)
        {
        }

        work();
    }

    abstract class Conditioner
    {
        abstract boolean condition();
    }

    private void setAllAlivedVotable()
    {
        for (Participant participant : getAliveParticipants())
        {
            votees.add(participant.toString());
        }
    }
    
    public void checkIfBlamedThe长老(Participant tmp)
    {
        if (tmp.role == Role.长老)
        {
            blameTheElder = true;
            sendInfoToPartial("长老被冤死!!!", getAliveParticipants());
        }
    }

    private void sendInfoToPartial(String msg, LinkedList<Participant> aliveParticipants)
    {
        sendInfoToPartial(msg, participants.toArray(new Participant[] {}));
    }

    private void work()
    {
        switch (state)
        {
            case wait:
            {
                stage("等待玩家加入", new Runnable()
                {
                    @Override
                    public void run()
                    {
                        waitAside(new Conditioner()
                        {
                            @Override
                            public boolean condition()
                            {
                                return participants.size() < playerNum;
                            }
                        });
                    }
                });
            }
            break;

            case gamebegin:
            {
                stage("人数已凑齐, 游戏马上开始", new Runnable()
                {
                    @Override
                    public void run()
                    {
                        iniGame();
                    }
                });

            }
            break;

            case shuffle:
            {
                stage("正在排座次和身份...", new Runnable()
                {
                    @Override
                    public void run()
                    {
                        Collections.shuffle(participants);
                        Collections.shuffle(roles);
                        sendToAll(constructMessage("players", StrUtils.join(participants, ',') + ",none"));

                        for (int i = 0; i < participants.size(); ++i)
                        {
                            Participant p = participants.get(i);
                            p.setRole(roles.get(i));
                            p.setStatus(Status.alive);
                            sendMsgToPartial("你的身份是" + p.getRole(), p);
                            sendToPartial(constructMessage("fromJson", p.toJson()), p);
                        }

                        sleepAWhile();
                        sendMsgToAll("所有人的身份已经各自通知完毕");
                        sendToAll(constructMessage("disable", "none"));
                    }
                });
            }
            break;

            case 盗贼:
            {
                stage("盗贼换牌阶段", new Runnable()
                {
                    @Override
                    public void run()
                    {
                        final Participant robber = getAliveParticipants(Role.盗贼).get(0);
                        voters.add(robber);

                        List<Role> tmp = roles.subList(playerNum, roles.size());
                        tmp.add(Role.盗贼);

                        for (Role role : tmp)
                        {
                            votees.add(role.toString());
                        }
                        voteSize = 1;

                        sendToPartial(constructMessage("players", StrUtils.join(votees, ',')), robber);

                        sendShiverToPartial("用鼠标选一张牌", robber);
                        waitForVotes();
                        
                        String result = voteHistory.values().toArray(new String[] {})[0];
                        robber.setRole(Role.valueOf(result));
                        sendShiverToPartial("你的身份变为" + result, robber);

                        sendToPartial(constructMessage("fromJson", robber.toJson()), robber);
                        sendToPartial(constructMessage("players", StrUtils.join(participants, ',') + ",none"), robber);
                        sendToPartial(constructMessage("disable", "none"), robber);
                    }
                });
            }
            break;

            case 丘比特:
            {
                stage("丘比特指定情侣阶段", new Runnable()
                {
                    @Override
                    public void run()
                    {
                        final Participant cupid = getAliveParticipants(Role.丘比特).get(0);
                        sendShiverToPartial("用鼠标指定两个情侣", cupid);
                        voters.add(cupid);
                        setAllAlivedVotable();
                        voteSize = 2;
                        
                        waitForVotes();
                        sendToPartial(constructMessage("toggleVote", ""), cupid);

                        Object[] tmp = voteHistory.values().toArray();

                        lover[0] = getParticipant(tmp[0].toString());
                        lover[1] = getParticipant(tmp[1].toString());

                        sendMsgToPartial("你选定的恋人是" + tmp[0] + "和" + tmp[1], cupid);

                        sendShiverToPartial(lover[0] + "是你的恋人, 他的身份是" + lover[0].role, lover[1]);
                        sendShiverToPartial(lover[1] + "是你的恋人, 他的身份是" + lover[1].role, lover[0]);
                    }
                });
            }
            break;

            case roundbegin:
            {
                stage("天黑请闭眼", new Runnable()
                {
                    @Override
                    public void run()
                    {
                        iniRound();
                    }
                });
            }
            break;

            case 预言家:
            {
                stage("预言家请验人", new Runnable()
                {
                    @Override
                    public void run()
                    {
                        Participant predictor = getAliveParticipants(Role.预言家).get(0);

                        Participant predicted = waitForOneVotee("请用鼠标指向一个要验的人", predictor);
                        sendShiverToPartial(predicted + "是" + (predicted.role.isGoodMan() ? "好人" : "坏人"), predictor);
                    }
                });
            }
            break;

            case 守卫:
            {
                stage("守护者请守护", new Runnable()
                {
                    @Override
                    public void run()
                    {
                        Participant protector = getAliveParticipants(Role.守卫).get(0);

                        if (lastProtected != none)
                        {
                            votees.remove(lastProtected);
                            sendToPartial(constructMessage("disable", lastProtected.name), protector);
                        }
                        
                        Participant protectedMan = waitForOneVotee("请用鼠标指向一个要守护的人", protector);

                        if (lastProtected.status != Status.dead)
                        {
                            sendToPartial(constructMessage("enable", lastProtected.name), protector);
                        }

                        sendShiverToPartial(protectedMan + "此轮不会被狼杀死", protector);
                        lastProtected = protectedMan;
                    }
                });
            }
            break;

            case 狼人:
            {
                stage("狼人请杀人", new Runnable()
                {
                    @Override
                    public void run()
                    {
                        List<Participant> wolves = getAliveParticipants(Role.狼人);
                        sendShiverToPartial(wolves + "是狼人. 用鼠标投票, 请统一意见", wolves);
                        voters = wolves;
                        setAllAlivedVotable();
                        voteSize = voters.size();
                        
                        sendToggleVote();
                        waitAside(new Conditioner()
                        {
                            @Override
                            boolean condition()
                            {
                                String choice = null;
                                for (String val : voteHistory.values())
                                {
                                    if (choice == null)
                                    {
                                        choice = val;
                                    }
                                    else if (!choice.equals(val))
                                    {
                                        return true;
                                    }
                                }

                                return voteSize != voteHistory.size();
                            }
                        });
                        sendToggleVote();

                        lastKilled = getParticipant(voteHistory.values().toArray(new String[] {})[0]);
                        sendMsgToPartial("你们杀了" + lastKilled, wolves);

                        if (lastProtected.equals(lastKilled))
                        {
                            lastKilled = none;
                        }
                        sendToPartial(constructHighlight(""), wolves);
                    }
                });
            }
            break;

            case 女巫:
            {
                stage("女巫救人毒人阶段", new Runnable()
                {
                    @Override
                    public void run()
                    {
                        Participant witch = getAliveParticipants(Role.女巫).get(0);
                        sendShiverToPartial("今天晚上" + (lastKilled == none ? "没有人死" : lastKilled + "死了"), witch);

                        if (lastKilled != none && save)
                        {
                            voters.add(witch);
                            voteSize = 1;
                            votees.add(none.name);
                            votees.add(lastKilled.name);

                            sendShiverToPartial("救他就把鼠标移动到他上面, 否则移动到none", witch);
                            sendToPartial(constructMessage("disable", "all"), witch);
                            sendToPartial(constructMessage("enable", "none"), witch);
                            sendToPartial(constructMessage("enable", lastKilled.name), witch);

                            Participant saved = getMaxVoted();

                            if (saved == lastKilled)
                            {
                                sendShiverToPartial("你救起了" + saved, witch);
                                lastKilled = none;
                                save = false;
                            }

                            sendToPartial(constructMessage("enable", "all"), witch);
                            LinkedList<Participant> tmp = new LinkedList<Participant>(getDeadParticipants());
                            tmp.addFirst(none);
                            sendToPartial(constructMessage("disable", StrUtils.join(tmp, ',')), witch);

                            clearVote();
                        }
                        else
                        {
                            sendShiverToPartial("你的解药已用完或今天没有人死, 暂停一个随机时间. ", witch);
                            sleepARandomTime();
                        }

                        if (poison)
                        {
                            voters.add(witch);
                            voteSize = 1;
                            setAllAlivedVotable();
                            votees.add("none");

                            sendToPartial(constructMessage("enable", "none"), witch);
                            sendShiverToPartial("请把鼠标移动到想毒死的人, 不毒就移动到none", witch);

                            lastPoisoned = getMaxVoted();

                            if (lastPoisoned != none)
                            {
                                sendShiverToPartial("你毒死了" + lastPoisoned, witch);
                                poison = false;

                                checkIfBlamedThe长老(lastPoisoned);
                            }

                            sendToPartial(constructMessage("disable", "none"), witch);
                        }
                        else
                        {
                            sendShiverToPartial("你的毒药用完了, 暂停一个随机时间. ", witch);
                            sleepARandomTime();
                        }
                    }
                });
            }
            break;

            case lastWords:
            {
                if (lastKilled != none)
                {
                    if (lastKilled.role == Role.长老 && lastKilled.status == Status.alive)
                    {
                        lastKilled.status = Status.half_alive;
                    }
                    else if (!diedLastNight.contains(lastKilled))
                    {
                        diedLastNight.add(lastKilled);
                    }
                }
                
                if (lastPoisoned != none && !diedLastNight.contains(lastPoisoned))
                {
                    diedLastNight.add(lastPoisoned);
                }

                for (Participant tmp : new LinkedList<>(diedLastNight))
                {
                    int i = 0;
                    if (lover[i++] == tmp || lover[i--] == tmp)
                    {
                        if (!diedLastNight.contains(lover[i]))
                        {
                            diedLastNight.add(lover[i]);
                        }
                    }
                }
                Collections.shuffle(diedLastNight);

                stage("天亮了. " + (diedLastNight.isEmpty() ? "平安夜" : (StrUtils.join(diedLastNight, ',')) + "在昨晚死了. "), new Runnable()
                {
                    @Override
                    public void run()
                    {
                        int cnt = 0;
                        for (Participant participant : diedLastNight)
                        {
                            if (cntOfDead + cnt++ > cntOfWolves)
                            {
                                sendMsgToAll(participant + "没有遗言");
                            }
                            else
                            {
                                voters.add(participant);
                                voteSize = 1;
                                votees.add("any");
                                sendMsgToAll(participant + "遗言阶段");
                                sendQueryInfoToPartial("请说遗言", "vote", participant);

                                waitForVotes();

                                sendMsgToAll(voteHistory.values().toArray()[0].toString(), participant.name, "遗言");

                                clearVote();
                            }

                            kill(participant);
                        }
                    }
                });
            }
            break;

            case day:
            {
                stage("发言阶段", new Runnable()
                {
                    @Override
                    public void run()
                    {
                        Participant first = diedLastNight.isEmpty() ? participants.get(0) : diedLastNight.get(0);
                        
                        if (sergent != none)
                        {
                            sendMsgToAll("警长组织发言");
                            sendShiverToPartial("用鼠标选定首个发言的人, 然后依次发言", sergent);

                            voters.add(sergent);
                            setAllAlivedVotable();
                            voteSize = 1;

                            first = getMaxVoted();
                            clearVote();
                        }

                        int i = 0;
                        for (Iterator iterator = participants.iterator(); iterator.hasNext(); ++i)
                        {
                            Participant tmp = (Participant) iterator.next();
                            if (tmp == first)
                            {
                                break;
                            }
                        }

                        LinkedList<Participant> addressers = new LinkedList<Participant>(participants.subList(i, participants.size()));
                        addressers.addAll(participants.subList(0, i));

                        for (Participant addresser : addressers)
                        {
                            if (addresser.status != Status.dead)
                            {
                                voters.add(addresser);
                                voteSize = 1;
                                votees.add("any");

                                sendMsgToAll(addresser + "发言");
                                sendQueryInfoToPartial("请发言", "vote", addresser);
                                waitForVotes();

                                sendMsgToAll(voteHistory.values().toArray()[0].toString(), addresser.name, "发言");
                                clearVote();
                            }
                        }
                    }
                });
            }
            break;

            case apply:
            {
                stage("竞选警长", new Runnable()
                {
                    @Override
                    public void run()
                    {
                        sendMsgToAll("大家自由发言并用鼠标投票");
                        voters.addAll(getAliveParticipants());
                        voteSize = getAliveParticipants().size();
                        setAllAlivedVotable();

                        sergent = getMaxVoted(true);
                        
                        sendMsgToAll(sergent + "当选为新警长");
                    }
                });
            }
            break;
            
            case vote:
            {
                stage("请大家投票, 把你的小手伸出来, 指向你心中的狼人! ", new Runnable()
                {
                    @Override
                    public void run()
                    {
                        voters.addAll(getAliveParticipants());
                        setAllAlivedVotable();
                        voteSize = voters.size();

                        Participant tmp = getMaxVoted(true);

                        checkIfBlamedThe长老(tmp);
                        
                        sendMsgToAll(tmp + "得票最多, 现在行刑!");
                        kill(tmp);
                        
                        int i = 0;
                        if (lover[i++] == tmp || lover[i--] == tmp)
                        {
                            sendMsgToAll(lover[i] + "和" + tmp + "是情侣, 被带死. ");
                            kill(lover[i]);
                        }
                    }
                });
            }
            break;
            
            case roundend:
            {
                stage("淫荡的一天结束了", new Runnable()
                {
                    @Override
                    public void run()
                    {
                        if (lover[0] != null && lover[0].status == Status.alive && (isGoodMan(lover[0].role) ^ isGoodMan(lover[0].role))) //如果人狼恋还活着
                        {
                            if (getAliveParticipants().size() == 2)
                            {
                                sendMsgToAll("恋人获胜: " + lover[0] + ", " + lover[1]);
                                gameEnd = true;
                            }
                        }
                        else
                        {
                            boolean tmp = true;
                            for (Participant participant : getAliveParticipants())
                            {
                                if (participant.role == Role.平民 || participant.role == Role.丘比特 || participant.role == Role.长老)
                                {
                                    tmp = false;
                                    break;
                                }
                            }
                            if (tmp)
                            {
                                sendMsgToAll("狼人获胜");
                                gameEnd = true;
                            }

                            tmp = true;
                            for (Participant participant : getAliveParticipants())
                            {
                                if (!isGoodMan(participant.role))
                                {
                                    tmp = false;
                                    break;
                                }
                            }
                            if (tmp)
                            {
                                sendMsgToAll("好人获胜");
                                gameEnd = true;
                            }
                        }
                    }
                });
            }
            break;

            case gameend:
            {
                StringBuilder sb = new StringBuilder("游戏结束, 所有人的身份如下: ");
                for (Participant participant : participants)
                {
                    sb.append("\n***********\n").append(participant.toFullString()).append("\n***********\n");
                }

                sendMsgToAll(sb.toString());
            }
            break;
            
            default:
                break;
        }
    }

    protected LinkedList<Participant> getDeadParticipants()
    {
        LinkedList<Participant> tmp = new LinkedList<>(participants);
        tmp.removeAll(getAliveParticipants());
        return tmp;
    }
    
    protected void kill(Participant died)
    {
        if (died == none)
        {
            return;
        }
        
        //        System.out.println("kill: " + died);
        
        cntOfDead++;
        died.status = Status.dead;
        
        if (sergent == died)
        {
            handOverSergent();
        }

        sendToPartial(constructMessage("disable", "all"), died);
        sendShiverToPartial("你死了", died);
        sendToAll(constructMessage("disable", died.name));
    }
    
    private void waitAside(final Conditioner conditioner)
    {
        Thread t = new Thread()
        {
            @Override
            public void run()
            {
                while (conditioner.condition() || participants.size() < playerNum)
                {
                    sleepAWhile();
                }
            };
        };

        t.start();

        try
        {
            t.join();
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }

    private void stage(String info, Runnable runnable)
    {
        if (blameTheElder && isGoodMensTurn())
        {
            sendMsgToAll(info + "\n******长老已被冤死, 所有特技失效******");
            sleepAWhile();
            sleepAWhile();
            sleepAWhile();
            
        }
        else
        {
            sendMsgToAll(info);
            sleepAWhile();
            sleepAWhile();
            sleepAWhile();
            
            try
            {
                runnable.run();
            }
            catch (Exception e)
            {
                if (!(e instanceof IndexOutOfBoundsException))
                {
                    e.printStackTrace();
                }
                
                try
                {
                    Thread.sleep(7000 + new Random().nextInt(5000));
                }
                catch (InterruptedException e1)
                {
                }
            }

            clearVote();
        }

        next();
    }

    private boolean isGoodMensTurn()
    {
        try
        {
            return isGoodMan(Role.valueOf(state.toString()));
        }
        catch (Exception e)
        {
            return false;
        }
    }
    
    public boolean isGoodMan(Role role)
    {
        return role != Role.狼人;
    }

    private void clearVote()
    {
        voteSize = 0;
        voteHistory.clear();
        voters.clear();
        votees.clear();
        
        for (Participant participant : participants)
        {
            participant.resetVoteCnt();
        }
    }

    private void sendShiverToPartial(String msg, List<Participant> receivers)
    {
        sendShiverToPartial(msg, receivers.toArray(new Participant[] {}));
    }

    private void sendShiverToPartial(String msg, Participant... receivers)
    {
        sendToPartial(constructMessage("shiver", "[振动]: " + msg), receivers);
    }

    public static String constructMessage(String type, String msg)
    {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("type", type);
        jsonObject.put("msg", msg);
        return jsonObject.toString();
    }

    private void sendMsgToAll(String msg)
    {
        sendMsgToAll(msg, GOD, SYSTEM_MSG);
    }

    public WSServer(LinkedList<Role> roles, Integer playerNum)
    {
        super(new InetSocketAddress(444), 10);
        this.playerNum = playerNum;
        this.roles = roles;
        
        //        new DebugFrame(this);
    }
    
    @Override
    public void onClose(WebSocket arg0, int arg1, String arg2, boolean arg3)
    {
        System.out.println("[" + arg0.getLocalSocketAddress() + "] existed!");
        
        exited.addFirst(getParticipant(arg0));
        participants.remove(exited.getFirst());
    }

    @Override
    public void onError(WebSocket arg0, Exception arg1)
    {
        System.err.println("\n******************\n" + (arg0 != null ? arg0.getLocalSocketAddress() : "") + "\n" + arg1.getLocalizedMessage() + "\n**************************************");
        arg1.printStackTrace();
    }

    public List<Participant> getParticipants()
    {
        return participants;
    }

    public List<Participant> getParticipants(Status status)
    {
        LinkedList<Participant> result = new LinkedList<Participant>();
        for (Participant participant : result)
        {
            if (participant.getStatus().equals(status))
            {
                result.add(participant);
            }
        }
        return result;
    }

    public List<Participant> getAliveParticipants(Role role)
    {
        LinkedList<Participant> result = new LinkedList<Participant>();
        for (Participant participant : participants)
        {
            if (participant.getRole().equals(role) && participant.status != Status.dead)
            {
                result.add(participant);
            }
        }
        return result;
    }

    public Participant getParticipant(WebSocket webSocket)
    {
        for (Participant participant : participants)
        {
            if (participant.getSocket().equals(webSocket))
            {
                return participant;
            }
        }
        return null;
    }

    public Participant getParticipant(String name)
    {
        for (Participant participant : participants)
        {
            if (participant.getName().equals(name))
            {
                return participant;
            }
        }
        return none;
    }

    LinkedList<Participant> getAliveParticipants()
    {
        LinkedList<Participant> result = new LinkedList<Participant>();
        for (Participant participant : participants)
        {
            if (participant.status != Status.dead)
            {
                result.add(participant);
            }
        }

        return result;
    }

    private Participant getMaxVoted()
    {
        return getMaxVoted(false);
    }

    /**
     * 已经配置好首次投票的候选者, 如果出现票数一样, 自动继续投票.
     */
    private Participant getMaxVoted(boolean openResult)
    {
        while (voters.size() > 0)
        {
            waitForVotes();

            if (openResult)
            {
                sendMsgToAll("投票结果:\n" + voteHistory);
            }

            LinkedList<Participant> maxVoted = new LinkedList<Participant>();
            
            for (Participant tmp : getAliveParticipants())
            {
                if (maxVoted.size() == 0)
                {
                    if (tmp.voteCnt != 0)
                    {
                        maxVoted.add(tmp);
                    }
                }
                else if (maxVoted.get(0).voteCnt > tmp.voteCnt)
                {
                }
                else if (maxVoted.get(0).voteCnt < tmp.voteCnt)
                {
                    maxVoted.clear();
                    maxVoted.add(tmp);
                }
                else
                {
                    maxVoted.add(tmp);
                }
            }
            
            if (maxVoted.isEmpty())
            {
                return none;
            }
            else if (maxVoted.size() == 1)
            {
                return maxVoted.get(0);
            }
            else
            {
                voters.removeAll(maxVoted);
                votees.clear();
                voteHistory.clear();
                voteSize = voters.size();
                
                for (Participant participant : maxVoted)
                {
                    votees.add(participant.name);
                }
                
                sendMsgToAll(votees + "得票数一样多, 都是" + maxVoted.get(0).voteCnt + "票. 请继续在他们之间投票! ");
            }
        }
        
        return none;
    }
    
    @Override
    public void onMessage(WebSocket socket, String message)
    {
        //        System.out.println("in: " + message);
        
        JSONObject jsonObject = JSONObject.fromObject(message);
        String msg = jsonObject.getString("msg");
        
        Participant participant = none;
        try
        {
            participant = getParticipant(socket);
        }
        catch (Exception e)
        {
        }

        switch (jsonObject.getString("type"))
        {
            case "register":
            {
                if (participants.size() == playerNum)
                {
                    socket.send(constructInfo("此服务器人数已满"));
                    socket.close();
                    return;
                }

                String name = msg.trim();
                boolean occupied = false;

                if (reserved(name))
                {
                    occupied = true;
                }
                else
                {
                    for (Participant p : participants)
                    {
                        if (p.getName().equals(name))
                        {
                            if (!p.getSocket().equals(socket))
                            {
                                occupied = true;
                                break;
                            }
                        }
                    }
                }

                if (!occupied)
                {
                    participants.add(new Participant(socket, name));
                    sendMsgToAll(name + " 被分配给 " + socket.getRemoteSocketAddress());
                }
                else
                {
                    socket.send(constructQueryInfo("名字已经占用, 请更改", "register"));
                }
            }
                break;

            case "msg":
            {
                String receiver = "all";
                try
                {
                    receiver = jsonObject.getString("to");
                }
                catch (Exception e)
                {
                }

                if (receiver.equals("all"))
                {
                    sendMsgToAll(msg, participant.getName(), "群聊");
                }
                else
                {
                    sendMsgToAll(participant + "向" + receiver + "发送了一条悄悄话");
                    sendMsgToPartial(msg, participant.getName(), "私聊", getParticipant(receiver));
                }
            }
                break;

            case "cancelVote":
            {
                if (canCancellVote(socket, msg))
                {
                    voteHistory.remove(participant.getName());
                    informVoteChange();
                }
            }
                break;

            case "vote":
            {
                if (canVote(socket, msg))
                {
                    getParticipant(voteHistory.put(participant.name + (state == State.丘比特 ? voteHistory.size() : ""), msg)).voteCnt -= participant == sergent && state == State.vote ? 2 : 1;
                    
                    if (state != State.狼人 && state != State.丘比特)
                    {
                        sendToPartial(constructMessage("toggleVote", ""), participant);
                    }
                    
                    if (state == State.apply || state == State.vote)
                    {
                        sendMsgToPartial("你选了" + msg, participant);
                    }
                    
                    try
                    {
                        Participant votedParticipant = getParticipant(msg);

                        if (votedParticipant != null)
                        {
                            if (state == State.vote && participant == sergent)
                            {
                                votedParticipant.voteCnt += 2;
                            }
                            else
                            {
                                votedParticipant.voteCnt++;
                            }
                        }
                    }
                    catch (Exception e)
                    {
                    }
                    
                    informVoteChange();
                }
                else
                {
                    socket.send(constructInfo("别乱投票"));
                }
            }
                break;

            case "kill":
            {

            }
                break;

            default:
                break;
        }
    }

    /**
     * 此方法假设你已设置好votees
     */
    private void handOverSergent()
    {
        sendMsgToAll("警长死了, 请移交警徽");
        sendShiverToPartial("用鼠标选择一个警徽接受者", sergent);
        clearVote();
        voters.add(sergent);
        voteSize = 1;
        setAllAlivedVotable();
        
        sergent = getMaxVoted();
        sendMsgToAll("新警长是" + sergent);
    }

    private void informVoteChange()
    {
        if (state == State.狼人)
        {
            sendToPartial(constructHighlight(StrUtils.join(voteHistory.entrySet(), ',')), getAliveParticipants(Role.狼人));
        }
    }

    private String constructHighlight(String msg)
    {
        return constructMessage("highlight", msg);
    }

    private boolean reserved(String name)
    {
        if (name.contains("[") || name.contains("]") || name.contains(",") || name.contains(":"))
        {
            return true;
        }
        
        for (Role role : Role.values())
        {
            if (name.contains(role.toString()))
            {
                return true;
            }
        }
        
        for (String str : new String[] { "all", "none", "any", GOD })
        {
            if (name.contains(str))
            {
                return true;
            }
        }

        return false;
    }

    private boolean canCancellVote(WebSocket socket, String votee)
    {
        Participant participant;
        try
        {
            participant = getParticipant(socket);
        }
        catch (Exception e)
        {
            e.printStackTrace();
            return false;
        }

        try
        {
            return participant.role == Role.狼人 && state == State.狼人 && voteHistory.get(participant.name).equals(votee);
        }
        catch (Exception e)
        {
            e.printStackTrace();
            return false;
        }
    }

    private boolean canVote(WebSocket socket, String votee)
    {
        Participant participant;
        try
        {
            participant = getParticipant(socket);
        }
        catch (Exception e)
        {
            e.printStackTrace();
            return false;
        }

        if (state == State.丘比特 && !voteHistory.isEmpty() && votee.equals(voteHistory.values().toArray()[0].toString()))
        {
            return false;
        }
        else if (state == State.狼人 && participant.role == Role.狼人)
        {
            return true;
        }
        else
        {
            return voters.contains(participant) && voteHistory.get(participant.name) == null && (votees.get(0).equals("any") || votees.contains(votee)) && voteHistory.size() < voteSize;
        }
    }

    private void sendToAll(String command)
    {
        //        System.out.println("out: " + command);
        
        for (WebSocket socket : connections())
        {
            socket.send(command);
        }
    }

    private void sendQueryInfoToPartial(String hint, String backType, Participant... participants)
    {
        sendToPartial(constructQueryInfo(hint, backType), participants);
    }

    private void sendMsgToAll(String msg, String from, String tag)
    {
        sendMsgToPartial(msg, from, tag, participants);
    }

    private void sendMsgToPartial(String msg, List<Participant> participants)
    {
        sendMsgToPartial(msg, participants.toArray(new Participant[] {}));
    }

    protected static void sendMsgToPartial(String msg, Participant... participants)
    {
        sendMsgToPartial(msg, GOD, SYSTEM_MSG, participants);
    }

    protected static void sendMsgToPartial(String msg, String from, String tag, Participant... participants)
    {
        msg = constructMsg(msg, "[" + tag + "] " + from);
        sendToPartial(msg, participants);
    }

    protected static void sendMsgToPartial(String msg, String from, String tag, List<Participant> participants)
    {
        sendMsgToPartial(msg, from, tag, participants.toArray(new Participant[] {}));
    }

    protected static void sendToPartial(String msg, List<Participant> participants)
    {
        sendToPartial(msg, participants.toArray(new Participant[] {}));
    }

    protected static void sendToPartial(String msg, Participant... participants)
    {
        //        System.out.println("out: " + msg + "\tto: " + Arrays.asList(participants));
        
        for (Participant participant : participants)
        {
            if (participant != none)
            {
                participant.socket.send(msg);
            }
        }
    }

    protected static String constructMsg(String msg, String from)
    {
        StringBuilder sb = new StringBuilder();
        try
        {
            sb.append("{\"type\":\"msg\",\"from\":\"").append(from).append("\",\"msg\":\"").append(Base64Utils.encode(msg.getBytes("UTF-8"))).append("\"}");
        }
        catch (Exception e)
        {
        }
        
        return sb.toString();
    }

    protected static String constructQueryInfo(String hint, String backType)
    {
        return constructQueryInfo(hint, backType, GOD);
    }

    protected static String constructQueryInfo(String hint, String backType, String from)
    {
        StringBuilder sb = new StringBuilder();
        sb.append("{\"type\":\"queryInfo\",\"from\":\"").append(from).append("\",\"hint\":\"").append(hint).append("\",\"backType\":\"").append(backType).append("\"}");
        return sb.toString();
    }

    @Override
    public void onOpen(WebSocket socket, ClientHandshake arg1)
    {
        //        System.out.println("[" + socket.getLocalSocketAddress() + "] entered!");
        socket.send(constructMsg("欢迎! ", GOD));

        if (!exited.isEmpty())
        {
            Participant lastExit = exited.getFirst();
            lastExit.socket = socket;
            participants.add(lastExit);

            sendToPartial(constructMessage("fromJson", lastExit.toJson()), lastExit);
            sendToPartial(constructMessage("players", getAliveParticipants().toString()), participants);
            sendInfoToPartial(constructMessage("disable", getDeadParticipants().toString()), lastExit);
        }
    }

    private void sendInfoToPartial(String msg, Participant... participants)
    {
        sendToPartial(constructInfo(msg), participants);
    }

    private String constructInfo(String msg)
    {
        StringBuilder sb = new StringBuilder();
        sb.append("{\"type\":\"info\",\"msg\":\"").append(msg).append("\"}");
        return sb.toString();
    }

    @Override
    public void start()
    {
        state = State.wait;
        new Thread()
        {
            @Override
            public void run()
            {
                work();
            }
        }.start();
        
        super.start();
        
        Scanner s = new Scanner(System.in);
        
        for (String command = s.nextLine(); !command.equals("stop"); command = s.nextLine())
        {
            JSONObject jsonObject = JSONObject.fromObject(command);

            String type = "";
            JSONArray to = new JSONArray();

            try
            {
                type = jsonObject.getString("type");
            }
            catch (Exception e)
            {
            }

            try
            {
                to = jsonObject.getJSONArray("to");
            }
            catch (Exception e)
            {
            }

            if (type.equals("$fun"))
            {
                try
                {
                    WSServer.class.getMethod(jsonObject.getString("fun"), String.class).invoke(this, jsonObject.getString("args"));
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
            }
            else
            {
                if (to.isEmpty())
                {
                    sendToAll(command);
                }
                else
                {
                    
                    for (Participant p : participants)
                    {
                        for (Object tmp : to)
                        {
                            if (p.getName().equals(tmp))
                            {
                                WSServer.sendToPartial(command, p);
                            }
                        }
                    }
                }

            }

        }
        
        try
        {
            stop();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
        s.close();
    }
    
    public static void main(String[] args) throws IOException, InterruptedException
    {
        Role[] roles = null;
        String[] roleStrs = args[0].split(",");

        roles = new Role[roleStrs.length];

        for (int i = 0; i < roles.length; i++)
        {
            roles[i] = Role.valueOf(roleStrs[i].trim());
        }

        WSServer server = new WSServer(new LinkedList<Participant.Role>(Arrays.asList(roles)), Integer.valueOf(args[1]));
        server.start();
    }

    public static void sleepAWhile()
    {
        try
        {
            Thread.sleep(1000);
        }
        catch (InterruptedException e)
        {
        }
    }

    private void sleepARandomTime()
    {
        for (int i = 3 + new Random().nextInt(20); i > 0; --i)
        {
            sleepAWhile();
        }
    }
    
    public void waitForVotes()
    {
        sendToggleVote();
        waitAside(new Conditioner()
        {
            @Override
            boolean condition()
            {
                return voteHistory.size() < voteSize;
            }
        });
    }
    
    public void sendToggleVote()
    {
        sendToPartial(constructMessage("toggleVote", ""), voters);
    }

    private Participant waitForOneVotee(String hint, Participant 预言家)
    {
        sendShiverToPartial(hint, 预言家);
        voters.add(预言家);
        setAllAlivedVotable();
        voteSize = 1;
        
        Participant predicted = getMaxVoted();
        return predicted;
    }
}
